class DoubleNode {
  constructor(data) {
    this.pre = null
    this.data = data
    this.next = null
  }
}

class DoubleNodeList {
  constructor() {
    this.head = null
    this.length = 0
    this.tail = null
  }

  append(data) {
    const node = new DoubleNode(data)
    this.tail = node
    if (this.length === 0) {
      this.head = node
      this.length += 1
    } else {
      let thatNode = this.head
      while (thatNode.next) {
        thatNode = thatNode.next
      }
      node.pre = thatNode
      thatNode.next = node
      this.length += 1
    }
  }
  insert(position, data) {
    if (position < 0 || position > this.length) return false
    const node = new DoubleNode(data)
    if (position === 0) {
      if (this.head) {
        this.head.pre = node
      }
      if (this.length === 0) {
        this.tail = node
      }
      node.next = this.head
      this.head = node
      this.length += 1
    } else {
      if (position === this.length) {
        this.tail = node
      }
      let thatNode = this.head
      for (let i = 0; i < position - 1; ++i) {
        thatNode = thatNode.next
      }
      if (thatNode.next) {
        thatNode.next.pre = node
      }
      node.pre = thatNode
      node.next = thatNode.next
      thatNode.next = node
      this.length += 1
    }
    return true
  }
  toString() {
    let str = ''
    let thatNode = this.head
    while (thatNode) {
      str += ` ${thatNode.data}`
      thatNode = thatNode.next
    }
    return str
  }
  forwardString() {
    let str = ''
    let thatNode = this.tail
    while (thatNode) {
      str += ` ${thatNode.data}`
      thatNode = thatNode.pre
    }
    return str
  }
  getbackward(position) {
    let thatNode = this.head
    for (let i = 0; i < position; ++i) {
      thatNode = thatNode.next
    }
    return thatNode
  }
  getforward(position) {
    let thatNode = this.tail
    for (let i = this.length - 1; i > position; --i) {
      thatNode = thatNode.pre
    }
    return thatNode
  }
  get(position) {
    if (position < 0 || position >= this.length) return null
    return this.getPosition(position).data
  }
  getPosition(position) {
    if (position > this.length / 2) {
      return this.getforward(position)
    } else {
      return this.getbackward(position)
    }
  }

  indexOf(data) {
    let thatNode = this.head
    for (let i = 0; i < this.length; ++i) {
      if (data === thatNode.data) {
        return i
      } else {
        thatNode = thatNode.next
      }
    }
    return -1
  }
  update(position, data) {
    if (position < 0 || position >= this.length) return false
    this.getPosition(position).data = data
    return true
  }
  removeAt(position) {
    if (position < 0 || position >= this.length) return null
    let thatNode = this.head
    if (this.length === 1) {
      this.head = null
      this.tail = null
      return thatNode
    } else {
      if (position === 0) {
        this.head.next.pre = null
        this.head = this.head.next
      } else if (position === this.length - 1) {
        thatNode = this.tail
        this.tail.pre.next = null
        this.tail = this.tail.pre
      } else {
        thatNode = this.getPosition(position)
        thatNode.pre.next = thatNode.next
        thatNode.next.pre = thatNode.pre
      }
    }
    this.length -= 1
    return thatNode.data
  }
  remove(data) {
    return !!this.removeAt(this.indexOf(data))
  }
  size() {
    return this.length
  }
  isEmpty() {
    return this.length === 0
  }
}

const list = new DoubleNodeList()
list.append(1)
list.append(2)
list.append(3)
// list.insert(0, 4)
// console.log(list.get(2))
// list.update(0, 6)
// console.log(list.indexOf(3))
console.log(list.removeAt(2))
// list.remove(1)
console.log(list.toString())
console.log(list.forwardString())
// console.log(list)
